#ifndef __PAGE_H_
#define __PAGE_H_

#include "types.h"
/* virtual address structure:
 * 63-39 	38-30	29-21	20-12	11-0
 * Reserved	Index3	Index2	Index1 Offset
 */
// virtual address to page table index
// sv39 has a 3 level page table, calculating methods vary by different level
#define VA2PGTABLE_INDEX(va, level) ((va >> (12 + (level - 1) * 9)) & 0x1ff)
// page table entry to physical address
#define PTE2PA(pte) (pte >> 10 << 12)
// physical address to page table entry
#define PA2PTE(pa, perm) ((pa >> 12 << 10) | perm)

#define SV39 0x8L

#define ENTRIES_PER_PAGE 512

#define PTE_V 1
#define PTE_R 1L << 1
#define PTE_W 1L << 2
#define PTE_X 1L << 3
#define PTE_U 1L << 4
#define PTE_G 1L << 5

/* page table(directory) entry: each for 8 bytes
 * 63-54	53-10	9-8		7	6	5	4	3	2	1	0
 *Reserved	 PPN	RSW		D	A 	G	U	X	W	R	V
 * PPN: Physical page number
 * RSW: not used
 * D: dirty
 * A: access
 * G: global, this page belongs to all page tables?
 * U: user, this page belongs to user not supervisor
 * X: executable:
 * W: writable
 * R: readable
 * V: 1->valid,0->invalid
 * X or W or R = 0 for pde_l2 and pde_l3
 */
typedef uint64 pte_l1;
typedef uint64 pde_l2;
typedef uint64 pde_l3;
struct pgtable_l1 {
	pte_l1 entries[ENTRIES_PER_PAGE];
};

struct pgtable_l2 {
	pde_l2 entries[ENTRIES_PER_PAGE];
};

struct pgtable_l3 {
	pde_l3 entries[ENTRIES_PER_PAGE];
};

/* @brief: virtual memory address
 * 	every proc has a vma list to indicate the user virtual address
 */
struct vma {
	struct linked_list *next;
	uint64 start_addr;
	uint64 size;
	uint64 flags;
	uint32 count;
};

// from page.c
extern struct pgtable_l3 kpgtable;

void page_init();
void smode_map_pages(struct pgtable_l3 *pgtable);
void map_pages(struct pgtable_l3 *table_ptr3, uint64 va, uint64 pa, uint64 size, uint64 perm);
void map_a_page(struct pgtable_l3 *table_ptr3, uint64 va, uint64 pa, uint64 perm);
uint64 va2pa(uint64 va, struct pgtable_l3 *table_ptr3);

#endif
